#ifndef __ATOMIC22_H_
#define __ATOMIC22_H_

#include<stdint.h>
#ifdef __GNUC__

typedef struct { uint32_t counter; } atomic_t;
#define ATOMIC_INIT(i) {i}
#define atomic_dec_return(v) (atomic_sub_return(v, 1))
#define atomic_inc_return(v) (atomic_add_return(v, 1))
#define atomic_init(v, i) (v)->counter = i
static inline uint32_t atomic_add_return(atomic_t *v, uint32_t i) { return (__sync_add_and_fetch(&v->counter, i)); }
static inline uint32_t atomic_cas(atomic_t *v, uint32_t oldval, uint32_t newval) { return (__sync_bool_compare_and_swap(&v->counter, oldval, newval)); }
static inline uint32_t atomic_cmpxchg(atomic_t *v, uint32_t oldval, uint32_t newval) { return (__sync_val_compare_and_swap(&v->counter, oldval, newval)); }
static inline uint32_t atomic_read(const atomic_t *v) { return (*(volatile uint32_t *)&(v)->counter); }
static inline uint32_t atomic_sub_return(atomic_t *v, uint32_t i) { return (__sync_sub_and_fetch(&v->counter, i)); }
static inline uint32_t atomic_xchg(atomic_t *v, uint32_t newval) { return (__sync_lock_test_and_set(&v->counter, newval)); }
static inline void atomic_add(atomic_t *v, uint32_t i) { __sync_fetch_and_add(&v->counter, i); }
static inline void atomic_dec(atomic_t *v) { __sync_fetch_and_sub(&v->counter, 1); }
static inline void atomic_inc(atomic_t *v) { __sync_fetch_and_add(&v->counter, 1); }
static inline void atomic_reset(atomic_t *v) { __sync_lock_release(&v->counter); }
static inline void atomic_set(atomic_t *v, uint32_t i) { v->counter = i; }
static inline void atomic_sub(atomic_t *v, uint32_t i) { __sync_fetch_and_sub(&v->counter, i); }

typedef struct { uint64_t counter; } atomic64_t;
#define ATOMIC64_INIT(i) {i}
#define atomic64_dec_return(v) (atomic64_sub_return(v, 1))
#define atomic64_inc_return(v) (atomic64_add_return(v, 1))
#define atomic64_init(v, i) (v)->counter = i
#define atomic_destroy(v)
static inline uint32_t atomic64_cas(atomic64_t *v, uint64_t oldval, uint64_t newval) { return (__sync_bool_compare_and_swap(&v->counter, oldval, newval)); }
static inline uint64_t atomic64_add_return(atomic64_t *v, uint64_t i) { return (__sync_add_and_fetch(&v->counter, i)); }
static inline uint64_t atomic64_cmpxchg(atomic64_t *v, uint64_t oldval, uint64_t newval) { return (__sync_val_compare_and_swap(&v->counter, oldval, newval)); }
static inline uint64_t atomic64_read(const atomic64_t *v) { return (*(volatile uint64_t *)&(v)->counter); }
static inline uint64_t atomic64_sub_return(atomic64_t *v, uint64_t i) { return (__sync_sub_and_fetch(&v->counter, i)); }
static inline uint64_t atomic64_xchg(atomic64_t *v, uint64_t newval) { return (__sync_lock_test_and_set(&v->counter, newval)); }
static inline void atomic64_add(atomic64_t *v, uint64_t i) { __sync_fetch_and_add(&v->counter, i); }
static inline void atomic64_dec(atomic64_t *v) { __sync_fetch_and_sub(&v->counter, 1); }
static inline void atomic64_inc(atomic64_t *v) { __sync_fetch_and_add(&v->counter, 1); }
static inline void atomic64_reset(atomic_t *v) { __sync_lock_release(&v->counter); }
static inline void atomic64_set(atomic64_t *v, uint64_t i) { v->counter = i; }
static inline void atomic64_sub(atomic64_t *v, uint64_t i) { __sync_fetch_and_sub(&v->counter, i); }

#else
#warning "atomic use lock"
#define ATOMIC_LOCK(v) pthread_mutex_lock(&v->lock)
#define ATOMIC_UNLOCK(v) pthread_mutex_unlock(&v->lock)

typedef struct { pthread_mutex_t lock; uint32_t counter; } atomic_t;
#define atomic_dec_return(v) atomic_sub_return((v), 1)
#define atomic_destroy(v) pthread_mutex_destroy(&v->lock)
#define atomic_inc_return(v) atomic_add_return((v), 1)
#define atomic_init(v, i) { pthread_mutex_init(&v->lock, NULL); (v)->counter = i; }
#define atomic_read(v) (*(volatile uint32_t *)&(v)->counter)
#define atomic_set(v, i) (((v)->counter) = (i))
static inline uint32_t atomic_add_return(atomic_t *v, uint32_t i) { ATOMIC_LOCK(v); uint32_t t = v->counter; t += i; v->counter = t; ATOMIC_UNLOCK(v); return t; }
static inline uint32_t atomic_sub_return(atomic_t *v, uint32_t i) { ATOMIC_LOCK(v); uint32_t t = v->counter; t -= i; v->counter = t; ATOMIC_UNLOCK(v); return t; }
static inline void atomic_add(atomic_t *v, uint32_t i) { atomic_add_return(i, v); }
static inline void atomic_dec(atomic_t *v) { atomic_sub_return(1, v); }
static inline void atomic_inc(atomic_t *v) { atomic_add_return(1, v); }
static inline void atomic_sub(atomic_t *v, uint32_t i) { atomic_sub_return(i, v); }

typedef struct { pthread_mutex_t lock; uint64_t counter; } atomic64_t;
#define atomic64_dec_return(v) atomic64_sub_return((v), 1)
#define atomic64_inc_return(v) atomic64_add_return((v), 1)
#define atomic64_init(v, i) { pthread_mutex_init(&v->lock, NULL); (v)->counter = i; }
#define atomic64_read(v) (*(volatile uint64_t *)&(v)->counter)
#define atomic64_set(v, i) (((v)->counter) = (i))
static inline uint64_t atomic64_add_return(atomic64_t *v, uint64_t i) { ATOMIC_LOCK(v); uint64_t t = v->counter; t += i; v->counter = t; ATOMIC_UNLOCK(v); return t; }
static inline uint64_t atomic64_sub_return(atomic64_t *v, uint64_t i) { ATOMIC_LOCK(v); uint64_t t = v->counter; t -= i; v->counter = t; ATOMIC_UNLOCK(v); return t; }
static inline void atomic64_add(atomic64_t *v, uint64_t i) { atomic64_add_return(i, v); }
static inline void atomic64_dec(atomic64_t *v) { atomic64_sub_return(v, 1); }
static inline void atomic64_inc(atomic64_t *v) { atomic64_add_return(v, 1); }
static inline void atomic64_sub(atomic64_t *v, uint64_t i) { atomic64_sub_return(v, i); }
#endif

#endif
